package com.wangyu.talents.web.security.filter;

import com.wangyu.talents.web.security.shiro.jwt.JWTToken;
import java.io.IOException;
import java.net.URLEncoder;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * JWT过滤器
 *
 * @author wangyu
 * @Date 2018/9/12 15:27
 * @Version 1.0
 */
public class JWTFilter extends BasicHttpAuthenticationFilter {

  /**
   * slf4j
   */
  private Logger logger = LoggerFactory.getLogger(JWTFilter.class);

  /**
   * 判断用户是登录操作
   */
  @Override
  protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
    HttpServletRequest hRequest = (HttpServletRequest) request;
    String token = hRequest.getHeader("token");       //取出请求投中的token
    return token != null;
  }

  /**
   * 如果带有token，则开始检查token，否则直接通过
   */
  @Override
  protected boolean isAccessAllowed(ServletRequest request, ServletResponse response,
      Object mappedValue) {
    if (isLoginAttempt(request, response)) {
      try {
        executeLogin(request, response);
      } catch (Exception e) {
        responseError(response, e.getMessage());
      }
    }

    //如果请求头不存在 Token，则可能是执行登陆操作或者是游客状态访问，无需检查 token，直接返回 true
    return true;
  }

  /**
   * 执行登录操作
   */
  @Override
  protected boolean executeLogin(ServletRequest request, ServletResponse response)
      throws Exception {
    HttpServletRequest httpServletRequest = (HttpServletRequest) request;
    String token = httpServletRequest.getHeader("token");
    JWTToken jwtToken = new JWTToken(token);
    //提交给realm执行登录,有异常则会抛出
    getSubject(request, response).login(jwtToken);
    //如果没有异常则返回true，表示登录成功
    return true;
  }

  /**
   * 跨域处理
   */
  @Override
  protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
    HttpServletRequest httpServletRequest = (HttpServletRequest) request;
    HttpServletResponse httpServletResponse = (HttpServletResponse) response;
    httpServletResponse
        .setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
    httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
    httpServletResponse.setHeader("Access-Control-Allow-Headers",
        httpServletRequest.getHeader("Access-Control-Request-Headers"));
    // 跨域时会首先发送一个option请求，这里我们给option请求直接返回正常状态
    if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
      httpServletResponse.setStatus(HttpStatus.OK.value());
      return false;
    }
    return super.preHandle(request, response);
  }

  /**
   * 将非法请求跳转到 /unauthorized/**
   */
  private void responseError(ServletResponse response, String message) {
    try {
      HttpServletResponse httpServletResponse = (HttpServletResponse) response;
      //设置编码，否则中文字符在重定向时会变为空字符串
      message = URLEncoder.encode(message, "UTF-8");
      httpServletResponse.sendRedirect("/unauthorized/" + message);
    } catch (IOException e) {
      logger.error(e.getMessage());
    }
  }
}
